﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SIMCObjetoNegocio;

namespace SIMCRepositorio
{
    public interface IRepositorioPersona
    {
        Persona Buscar(int p_IdPersona);
        PersonaPlana BuscarDTO (int p_IdPersona);
        IList<Relacion> BuscarListaRelaciones(int p_IdPersona);
        void Guardar(Persona p_Persona);
        Relacion BuscarRelacion(int p_IdPersona1, int p_IdPersona2);
        void GuardarRelacion(Relacion p_Relacion);
    }

    public class RepositorioPersona : Database, IRepositorioPersona
    {
        public void Guardar(Persona p_Persona)
        {
            try
            {
                per_personas persona = new per_personas()
                {
                    per_icodigo = p_Persona.Id,
                    per_spais = p_Persona.Pais,
                    per_sncorto = p_Persona.NombreCorto,
                    per_ctipo = p_Persona.GetType().Equals(typeof(PersonaNatural)) ? Valores.PersonaNatural : Valores.PersonaJuridica,
                    per_iresp_relac = p_Persona.IdRespRelacion,
                    per_iapoderado = p_Persona.IdApoderado,
                    per_sid_otro = p_Persona.OtroDocIdPais,
                    per_icreador = p_Persona.idCreador,
                    per_fcreacion = p_Persona.FechaCreacion,
                    per_stelefono = p_Persona.TelefonoPrincipal != null ? p_Persona.TelefonoPrincipal.Numero : null
                };

                if (EsNueva(persona))
                {
                    base.Insertar(persona);

                    if (EsPersonaNatural(p_Persona))
                    {
                        per_naturales pernatural = MapPersonaNatural(p_Persona, persona);

                        base.Insertar(pernatural);
                    }
                    else
                    {
                        per_juridicas perjuridica = MapPersonaJuridica(p_Persona, persona);

                        base.Insertar(perjuridica);
                    }
                }
                else
                {
                    base.Modificar(persona);

                    if (EsPersonaNatural(p_Persona))
                    {
                        per_naturales pernatural = MapPersonaNatural(p_Persona, persona);

                        base.Modificar(pernatural);
                    }
                    else
                    {
                        per_juridicas perjuridica = MapPersonaJuridica(p_Persona, persona);

                        base.Modificar(perjuridica);
                    }
                }

                p_Persona.Id = persona.per_icodigo;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private static per_juridicas MapPersonaJuridica(Persona p_Persona, per_personas persona)
        {
            PersonaJuridica p = p_Persona as PersonaJuridica;

            per_juridicas perjuridica = new per_juridicas()
            {
                per_icodigo = persona.per_icodigo,
                pju_fregistro = p.FechaDeRegistro,
                pju_snombre = p.Nombre,
                pju_sregistro = p.DatosDeRegistro,
            };

            return perjuridica;
        }

        private static per_naturales MapPersonaNatural(Persona p_Persona, per_personas persona)
        {
            PersonaNatural p = p_Persona as PersonaNatural;

            per_naturales pernatural = new per_naturales()
            {
                per_icodigo = persona.per_icodigo,
                pna_snombre = p.Nombres,
                pna_sapellidos = p.Apellidos,
                pna_cecivil = p._EstadoCivil,
                pna_csexo = p.Sexo == enumSexo.Masculino ? Valores.Masculino : Valores.Femenino,
                pna_fnacimiento = p.FechaNacimiento,
                pna_fvenc_id = p.FechaVencimientoId,                
                pna_stitulo = p.Titulo,
                pna_scelular = p.Celular != null ? p.Celular.Numero : null,
                pna_semail = p.Email != null ? p.Email.Direccion : null
            };

            return pernatural;
        }

        private static bool EsPersonaNatural(Persona p_Persona)
        {
            return p_Persona.GetType() == typeof(PersonaNatural);
        }

        private static bool EsNueva(per_personas persona)
        {
            return persona.per_icodigo == 0;
        }

        public Persona Buscar(int p_IdPersona)
        {
            try
            {
                var query = from persona in Context.per_personas
                            join relacion in Context.per_personas
                                on persona.per_iresp_relac equals relacion.per_icodigo into RelacionPersona
                            from relacion in RelacionPersona.DefaultIfEmpty()
                            join pais in Context.zon_paises
                                on persona.per_spais equals pais.zpa_scodigo into PaisPersona
                            from pais in PaisPersona.DefaultIfEmpty()
                            join natural in Context.per_naturales
                                on persona.per_icodigo equals natural.per_icodigo into NaturalPersona
                            from natural in NaturalPersona.DefaultIfEmpty()
                            join juridica in Context.per_juridicas
                                on persona.per_icodigo equals juridica.per_icodigo into JuridicaPersona
                            from juridica in JuridicaPersona.DefaultIfEmpty()
                            where persona.per_icodigo == p_IdPersona
                            select new 
                            { 
                                Persona = persona,
                                Relacion = relacion,
                                Pais = pais,
                                Natural = natural,
                                Juridica = juridica
                            };

                var temp = query.Single();

                if (temp.Persona.per_ctipo == Valores.PersonaJuridica)
                {
                    return new PersonaJuridica
                    {
                        Id = temp.Persona.per_icodigo,
                        NombreCorto = temp.Persona.per_sncorto,
                        Pais = temp.Persona.per_spais,
                        NombrePais = temp.Pais.zpa_snombre,
                        DocIdPais = temp.Persona.per_sid_pais,
                        TipoNJ = temp.Persona.per_ctipo,
                        IdRespRelacion = temp.Persona.per_iresp_relac,
                        NombreResponsableRelacion = temp.Relacion.per_sncorto,
                        IdApoderado = temp.Persona.per_iapoderado,
                        OtroDocIdPais = temp.Persona.per_sid_otro,
                        Notas = temp.Persona.per_snotas,
                        idCreador = temp.Persona.per_icreador,
                        TelefonoPrincipal = new Telefono
                            (temp.Persona.per_stelefono, "Celular", temp.Pais.zpa_sddi),
                        Nombre = temp.Juridica.pju_snombre,
                        DatosDeRegistro = temp.Juridica.pju_sregistro,
                        FechaDeRegistro = temp.Juridica.pju_fregistro,
                        FechaCreacion = temp.Persona.per_fcreacion,
                        NombreIdentificacionSegunPais = temp.Pais.zpa_sijuridicos
                    };
                }
                else
                {
                    return new PersonaNatural
                    {
                        Id = temp.Persona.per_icodigo,
                        NombreCorto = temp.Persona.per_sncorto,
                        Pais = (temp.Persona.per_spais != null) ? temp.Persona.per_spais:string.Empty,
                        NombrePais = (temp.Pais.zpa_snombre!=null) ? temp.Pais.zpa_snombre:string.Empty,
                        NombreIdentificacionSegunPais = (temp.Pais.zpa_sinaturales != null) ? temp.Pais.zpa_sinaturales:string.Empty,
                        DocIdPais = (temp.Persona.per_sid_pais!=null) ? temp.Persona.per_sid_pais:string.Empty,
                        TipoNJ = (temp.Persona.per_ctipo!=null) ? temp.Persona.per_ctipo:string.Empty,
                        IdRespRelacion = (temp.Persona.per_iresp_relac!=null) ? temp.Persona.per_iresp_relac : 0,
                        NombreResponsableRelacion = (temp.Relacion != null) ? temp.Relacion.per_sncorto:string.Empty,
                        IdApoderado = (temp.Persona.per_iapoderado!=null) ? temp.Persona.per_iapoderado : 0,
                        OtroDocIdPais = (temp.Persona.per_sid_otro!=null) ? temp.Persona.per_sid_otro: string.Empty,
                        Notas = (temp.Persona.per_snotas != null) ? temp.Persona.per_snotas : string.Empty,                       
                        idCreador = (temp.Persona.per_icreador!=null) ? temp.Persona.per_icreador: 0,
                        TelefonoPrincipal = (temp.Persona.per_stelefono != null)? new Telefono
                           (temp.Persona.per_stelefono , "Celular", temp.Pais.zpa_sddi): new Telefono(),
                        Nombres = temp.Natural.pna_snombre,
                        Apellidos = temp.Natural.pna_sapellidos,
                        Sexo = temp.Natural.pna_csexo.ToUpper() == Valores.Masculino ? enumSexo.Masculino : enumSexo.Femenino,
                        FechaNacimiento = (temp.Natural.pna_fnacimiento!=null) ? temp.Natural.pna_fnacimiento : DateTime.MinValue,
                        FechaVencimientoId = (temp.Natural.pna_fvenc_id!=null) ? temp.Natural.pna_fvenc_id : DateTime.MinValue,
                        Titulo = (temp.Natural.pna_stitulo!=null) ? temp.Natural.pna_stitulo : string.Empty,
                        Celular = (temp.Natural.pna_scelular!=null) ? new Telefono(temp.Natural.pna_scelular, "Celular", temp.Pais.zpa_sddi): new Telefono(),
                        Email = new DireccionElectronica { Direccion = temp.Natural.pna_semail },
                        _EstadoCivil = temp.Natural.pna_cecivil,
                    };
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }


        public PersonaPlana BuscarDTO(int p_IdPersona)
        {
            try
            {
                var query = from persona in Context.per_personas
                            where persona.per_icodigo == p_IdPersona
                            select new PersonaPlana
                            {
                                Id = persona.per_icodigo,
                                NombreCorto = persona.per_sncorto,
                                Pais = persona.per_spais,
                                DocIdPais = persona.per_sid_pais,
                                TipoNJ = persona.per_ctipo,
                            };

                return query.SingleOrDefault();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public IList<Relacion> BuscarListaRelaciones(int p_IdPersona)
        {
            try
            {
                var query = (from relacion in Context.per_relaciones
                             join persona1 in Context.per_personas
                                 on relacion.pre_icodper_1 equals persona1.per_icodigo
                             join persona2 in Context.per_personas
                                 on relacion.pre_icodper_2 equals persona2.per_icodigo
                             join valor in Context.cla_valores
                                 on relacion.pre_stiporel equals valor.cav_scodigo
                             where valor.cav_satributo == Valores.TipoRelacion && relacion.pre_icodper_1 == p_IdPersona
                             select new Relacion
                                 {
                                     IdPersona1 = relacion.pre_icodper_1,
                                     NombrePersona_1 = persona1.per_sncorto,
                                     IdPersona2 = relacion.pre_icodper_2,
                                     NombrePersona_2 = persona2.per_sncorto,
                                     TipoRelacion = relacion.pre_stiporel,
                                     TipoRelacionDescripcion = valor.cav_sdescripcion,
                                     FechaInicio = relacion.pre_finicio,
                                     FechaFinal = relacion.pre_ffinal,
                                     //Notas = relacion.pre_snotas TODO: Revisar por qué falla
                                 }
                            ).Union
                            (from relacion in Context.per_relaciones
                             join persona1 in Context.per_personas
                                 on relacion.pre_icodper_1 equals persona1.per_icodigo
                             join persona2 in Context.per_personas
                                 on relacion.pre_icodper_2 equals persona2.per_icodigo
                             join valor in Context.cla_valores
                                 on relacion.pre_stiporel equals valor.cav_scodigo
                             where valor.cav_satributo == Valores.TipoRelacion && relacion.pre_icodper_2 == p_IdPersona
                             select new Relacion
                                {
                                    IdPersona1 = relacion.pre_icodper_1,
                                    NombrePersona_1 = persona1.per_sncorto,
                                    IdPersona2 = relacion.pre_icodper_2,
                                    NombrePersona_2 = persona2.per_sncorto,
                                    TipoRelacion = relacion.pre_stiporel,
                                    TipoRelacionDescripcion = valor.cav_sdescripcion,
                                    FechaInicio = relacion.pre_finicio,
                                    FechaFinal = relacion.pre_ffinal,
                                    //Notas = relacion.pre_snotas
                                });

                return query.ToList();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public Relacion BuscarRelacion(int p_IdPersona1, int p_IdPersona2)
        {
            try 
            {
                var query = (from relacion in Context.per_relaciones
                             join persona1 in Context.per_personas
                                 on relacion.pre_icodper_1 equals persona1.per_icodigo
                             join persona2 in Context.per_personas
                                 on relacion.pre_icodper_2 equals persona2.per_icodigo
                             join valor in Context.cla_valores
                                 on relacion.pre_stiporel equals valor.cav_scodigo
                             where valor.cav_satributo == Valores.TipoRelacion 
                                    && relacion.pre_icodper_1 == p_IdPersona1
                                    && relacion.pre_icodper_2 == p_IdPersona2
                             select new Relacion
                             {
                                 IdPersona1 = relacion.pre_icodper_1,
                                 NombrePersona_1 = persona1.per_sncorto,
                                 IdPersona2 = relacion.pre_icodper_2,
                                 NombrePersona_2 = persona2.per_sncorto,
                                 TipoRelacion = relacion.pre_stiporel,
                                 TipoRelacionDescripcion = valor.cav_sdescripcion,
                                 FechaInicio = relacion.pre_finicio,
                                 FechaFinal = relacion.pre_ffinal,
                                 //Notas = relacion.pre_snotas TODO: Revisar por qué falla
                             }
                            );

                return query.SingleOrDefault(); 
            }
            catch (Exception ex)
            {
                throw ex;
            }

        }

        public void GuardarRelacion(Relacion p_Relacion)
        {
            try
            {
                per_relaciones t_Relacion = new per_relaciones()
                {
                    pre_icodper_1 = p_Relacion.IdPersona1,
                    pre_icodper_2 = p_Relacion.IdPersona2,
                    pre_finicio = p_Relacion.FechaInicio,
                    pre_ffinal = p_Relacion.FechaFinal,
                    pre_stiporel = p_Relacion.TipoRelacion
                };

                base.Insertar(t_Relacion);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}
